'''
Created on 28/03/2010

@author: miguel
'''

import pygame
import random
import sys
from BugExit import BugExit
from Tree import Tree
from BugManual import BugManual
from Bug import Bug
from vec2d import vec2d
from GameBoard import GameBoard
from Instruction import Instruction
from Box import Box
from EnemyPanel import EnemyPanel
from PlayerPanel import PlayerPanel
from Player import Player
from Computer import Computer
from InstructionsPanel import InstructionsPanel

class Game(object):
    ''' Main class of the game
    '''
    # Game parameters
    SCREEN_WIDTH = 800
    SCREEN_HIGH = 600
    BACKGROUND_IMAGE = './data/background.png'
    MUSIC_FILE = './data/country.mod'

    (PLAYER, COMPUTER, NOBODY) = range (3)

    INTRO_IMAGE1 = './data/intro_1.png'
    INTRO_IMAGE2 = './data/intro_2.png'
    MENU_IMAGE = './data/menu.png'
    END1_IMAGE = './data/end1.png'
    END2_IMAGE = './data/end2.png'


    def __init__(self):
        '''Initializes the basic information for the game
        '''
        
        pygame.init()
        # pygame.key.set_repeat(10,10) repeticion de teclas, seguramente no hace falta

        self.screen = pygame.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HIGH),0,32)
        self.background_image = pygame.image.load(self.BACKGROUND_IMAGE)
        self.intro_image1 = pygame.image.load(self.INTRO_IMAGE1)
        self.intro_image2 = pygame.image.load(self.INTRO_IMAGE2)
        self.menu_image = pygame.image.load(self.MENU_IMAGE)
        self.end1_image = pygame.image.load(self.END1_IMAGE)
        self.end2_image = pygame.image.load(self.END2_IMAGE)

        self.clock = pygame.time.Clock()
        self.paused = False
        self.game_board = GameBoard()

        self.trees = pygame.sprite.Group()
        pygame.mixer.music.load(self.MUSIC_FILE)

        self.winner = self.NOBODY

    def __quit(self):
        '''Exit the game
        '''
        
        sys.exit()

    def __draw(self):
        '''Draw all elements of the game: bug exists, boxes, bugs, panels and trees
        '''
        
        self.__draw_background()
        # draw bug exits
        for bug_exit in self.player.bug_exits:
            bug_exit.draw()
        for bug_exit in self.computer.bug_exits:
            bug_exit.draw()

        # draw boxes
        for user_box in self.player.user_boxes:
            user_box.draw()
        for com_box in self.computer.com_boxes:
            com_box.draw()

        # draw bugs
        for user_bug in self.player.user_bugs:
            user_bug.draw()
        for com_bug in self.computer.com_bugs:
            com_bug.draw()

        # draw panels
        self.player.player_panel.draw()
        self.computer.enemy_panel.draw()

        # draw trees in the screen
        for tree in self.trees:
            tree.draw()

        # draw the instruction panel
        self.instructions_panel.draw()

    def __draw_background(self):
        '''Draw the background for the game
        '''
        
        bg_rect = self.background_image.get_rect()
        self.screen.blit(self.background_image, bg_rect)

    def __create_obstacles(self):
        '''Create the obstacle structure for the game.
        
        Selects a random structure of the defined ones.
        '''
        
        self.tree_estructure = [[(0, 210), (30, 210), (60, 210), (90, 210), (120, 210), (150, 210), (180, 210), (210, 210), (180, 300), (210, 300), (240, 300), (270, 300), (300, 300), (330, 300), (360, 300), (390, 300), (360, 390), (390, 390), (420, 390), (450, 390), (480, 390), (510, 390), (540, 390)],
                                [(0, 210), (30, 210), (60, 210), (90, 210), (120, 210), (150, 210), (180, 210), (210, 210), (240, 210), (270, 210), (300, 210), (330, 210), (360, 210), (390, 210), (420, 210), (450, 210), (480, 210), (510, 210), (540, 210),
                                 (0, 420), (30, 420), (60, 420), (90, 420), (120, 420), (150, 420), (180, 420), (210, 420), (240, 420), (270, 420), (300, 420), (330, 420), (360, 420), (390, 420), (420, 420), (450, 420), (480, 420), (510, 420), (540, 420)],
                                [(0, 450), (30, 450), (60, 450), (90, 450), (120, 360), (150, 360), (180, 360), (210, 360), (210, 300), (240, 300), (270, 300), (300, 300), (330, 300), (300, 240), (330, 240), (360, 240), (390, 240), (420, 150), (450, 150), (480, 150), (510, 150), (540, 150)]]

        self.estructure_selected = random.randint(0, len(self.tree_estructure) - 1)
        for object in self.tree_estructure[self.estructure_selected]:
            self.trees.add(Tree(self.screen, self, self.background_image.get_rect(), object))

    def explosion(self, position):
        '''Given a position where a explosino took place, all objects in the screen are checked to see if they are affected and must be killed or destroyed.
        
        Keyword arguments:
        position -- vec2d position where the explosion happened
        
        '''
        
        # calculate affected positions
        # position double effect
        self.position0 = vec2d(position)
        # positions single effect
        self.position1 = vec2d(position) + vec2d(-30, 0)
        self.position2 = vec2d(position) + vec2d(0, -30)
        self.position3 = vec2d(position) + vec2d(30, 0)
        self.position4 = vec2d(position) + vec2d(0, 30)
        self.position_list = [self.position0, self.position1, self.position2, self.position3, self.position4]

        # checks if trees are affected by the explosion
        for tree in self.trees:
            tree.hit_tree(self.position_list)

        # checks if user boxes are affected by the explosion
        for user_box in self.player.user_boxes:
            user_box.hit_box(self.position_list)

        # checks if computes boxes are affected by the explosion
        for com_box in self.computer.com_boxes:
            com_box.hit_box(self.position_list)

        # checks if user bugs are affected by the explosion
        for user_bug in self.player.user_bugs:
            user_bug.hit_bug(self.position_list)
            
        # checks if computer bugs are affected by the explosion
        for com_bug in self.computer.com_bugs:
            com_bug.hit_bug(self.position_list)


    def __load_other_elements(self):
        '''Creates 3 very important parts: the player object, the computer object and the instruction panel.
        '''
        
        self.player = Player(self.screen, self, self.background_image.get_rect())
        self.computer = Computer(self.screen, self, self.background_image.get_rect())
        self.instructions_panel = InstructionsPanel(self.screen, self)

#    DELETE THIS FUNCTION
#    def is_position_available(self, sprite):
#        for tree in self.trees:
#            if pygame.sprite.collide_rect(sprite, tree):
#                return True
#            else:
#                pass
#        return False

    def intro(self):
        '''Shows the intro of the game
        '''
        
        self.intro = self.intro_image1
        bg_rect = self.intro_image1.get_rect()
        counter = 0
        skip_intro = False
        while True:
            time_passed = self.clock.tick(30)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.__quit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
                        skip_intro = True
            if skip_intro == True:
                break
            if counter > 200 and counter < 400:
                self.intro = self.intro_image2
            elif counter > 400:
                break
            counter = counter + 1
            self.screen.blit(self.intro, bg_rect)
            pygame.display.flip()

    def menu(self):
        '''Handles the main menu
        '''
        
        bg_rect = self.menu_image.get_rect()

        skip_intro = False
        while True:
            time_passed = self.clock.tick(30)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.__quit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_s:
                        skip_intro = True
            if skip_intro == True:
                break

            self.screen.blit(self.menu_image, bg_rect)
            pygame.display.flip()

    def run(self):
        ''' Entry point for the game
        '''
        self.intro()
        self.menu()
        self.start_game()

    def run_without_intro(self):
        '''Shortcut during the development to play the game without see the intro 
        '''
        
        self.menu()
        self.start_game()

    def start_game(self):
        '''Control the development of the game (main loop)
        '''
        
        self.__create_obstacles()
        self.__load_other_elements()

        pygame.mixer.music.play()

        # The main loop of the game
        while True:
            if not pygame.mixer.music.get_busy():
                pygame.mixer.music.play()

            time_passed = self.clock.tick(30)
            # game pause; we don't want to jump forward later
            if time_passed > 100:
                continue

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.__quit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_p:
                        self.paused = not self.paused
                    elif event.key == pygame.K_ESCAPE:
                        self.__quit()
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    (left_button, middle_button, right_button) = pygame.mouse.get_pressed()
                    if left_button:
                        self.instructions_panel.click(pygame.mouse.get_pos())

            if not self.paused:
                self.computer.update(time_passed)
                self.player.update(time_passed)
                self.instructions_panel.update()

                self.__draw()

            pygame.display.flip()
            # if someone won, exit the loop
            if self.winner != self.NOBODY:
                break

        if self.winner == self.PLAYER:
            pygame.mixer.music.stop()
            self.win_player()
        elif self.winner == self.COMPUTER:
            pygame.mixer.music.stop()
            self.win_computer()

    def win_player(self):
        '''Final movie if the player won
        '''
        
        self.end2 = self.end2_image
        bg_rect = self.end2_image.get_rect()

        skip_intro = False
        while True:
            time_passed = self.clock.tick(30)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.__quit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        self.__quit()
            if skip_intro == True:
                break

            self.screen.blit(self.end2, bg_rect)
            pygame.display.flip()

    def win_computer(self):
        '''Final movie if the computer won
        '''
        
        self.end1 = self.end1_image
        bg_rect = self.end1_image.get_rect()

        skip_intro = False
        while True:
            time_passed = self.clock.tick(30)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.__quit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        self.__quit()
            if skip_intro == True:
                break

            self.screen.blit(self.end1, bg_rect)
            pygame.display.flip()

if __name__ == '__main__':
    game = Game()
    game.run()